﻿/*
 * iec104link.hpp
 *
 *  Created on: 2017年2月4日
 *      Author: work
 */

#ifndef _DM_PROTOCOL_FRAME104LDU_HPP_
#define _DM_PROTOCOL_FRAME104LDU_HPP_

#include <dm/export.hpp>

#ifndef DM_API_PROTOCOL
#define DM_API_PROTOCOL DM_API_IMPORT
#endif

#include <dm/protocol/frame.hpp>
#include <dm/protocol/frame104apdu.hpp>

namespace dm{
namespace protocol{

class DM_API_PROTOCOL CFrame104Ldu:public CFrame{
public:
	typedef CFrame104Apdu apdu_t;

	enum{
		MaxLenOfAsdu = 249
	};

	/**
	 * 帧类型
	 */
	enum EType{
		I_Frame	= 0,	// 编号的信息传输
		S_Frame	= 1,	// 编号的监视功能
		U_Frame	= 2	// 未编号的控制功能
	};


	CFrame104Ldu( const EType& type=U_Frame );
	CFrame104Ldu( const CFrame104Ldu& frame );

	CFrame104Ldu& operator=( const CFrame104Ldu& frame );

	inline bool isIFrame()const{
		return (m_ctl.i.id0==0) && (m_ctl.i.id1==0);
	}

	inline bool isSFrame()const{
		return (m_ctl.s.id0==1)&&( m_ctl.s.id1==0 );
	}

	inline bool isUFrame()const{
		return (m_ctl.u.id0==3)&&(m_ctl.u.id1==0);
	}

	inline bool isAvaliableFrame()const{
		return isIFrame()||isSFrame()||isUFrame();
	}

	void setIFrame();
	void setSFrame();
	void setUFrame();

	inline bool isTestFr_avaliable()const{
		return m_ctl.u.testFr_avail!=0;
	}

	inline bool isTestFr_confirm()const{
		return m_ctl.u.testFr_conf!=0;
	}

	inline bool isStopDt_avaliable()const{
		return m_ctl.u.stopDt_avail!=0;
	}

	inline bool isStopDt_confirm()const{
		return m_ctl.u.stopDt_conf!=0;
	}

	inline bool isStartDt_avaliable()const{
		return m_ctl.u.startDt_avail!=0;
	}

	inline bool isStartDt_confirm()const{
		return m_ctl.u.startDt_conf!=0;
	}

	inline void setTestFr_avaliable( const bool& s=true ){
		m_ctl.u.testFr_avail = s?1:0;
	}

	inline void setTestFr_confirm( const bool& s=true ){
		m_ctl.u.testFr_conf = s?1:0;
	}

	inline void setStopDt_avaliable( const bool& s=true ){
		m_ctl.u.stopDt_avail = s?1:0;
	}

	inline void setStopDt_confirm( const bool& s=true ){
		m_ctl.u.stopDt_conf = s?1:0;
	}

	inline void setStartDt_avaliable( const bool& s=true ){
		m_ctl.u.startDt_avail = s?1:0;
	}

	inline void setStartDt_confirm( const bool& s=true ){
		m_ctl.u.startDt_conf = s?1:0;
	}

	inline dm::uint16 getRecvSeq()const{
		return m_ctl.s.rsq;
	}

	inline dm::uint16 getSendSeq()const{
		return m_ctl.i.ssq;
	}

	inline void setRecvSeq( const dm::uint16& seq ){
		m_ctl.s.rsq = (seq & 0x7FFF);
	}

	inline void setSendSeq( const dm::uint16& seq ){
		m_ctl.i.ssq = (seq & 0x7FFF);
	}

	inline const apdu_t& getApdu()const{
		return m_apduRef;
	}

	inline apdu_t& getApdu(){
		return m_apduRef;
	}

	inline const dm::uint8& getApduLen()const{
		return m_apduRef.getLen();
	}

	inline void releaseAsdu(){
		m_apduRef.checkData(0);
	}

	bool encode( CTxBuffer& buf )const;
	bool decode( const CRxBuffer& buf, const pos_t& end,pos_t& start,const CFrame* txFrame );


private:
	union{
		dm::uint32 all;
		dm::uint8 bytes[4];

		struct{
			dm::uint32 id0:1;	// 0
			dm::uint32 ssq:15;

			dm::uint32 id1:1;	// 0
			dm::uint32 rsql:15;
		}i;

		struct{
			dm::uint32 id0:16;	// 0x01
			dm::uint32 id1:1;	// 0
			dm::uint32 rsq:15;
		}s;

		struct{
			dm::uint32 id0:2;	// 3
			dm::uint32 startDt_avail:1;
			dm::uint32 startDt_conf:1;
			dm::uint32 stopDt_avail:1;
			dm::uint32 stopDt_conf:1;
			dm::uint32 testFr_avail:1;
			dm::uint32 testFr_conf:1;

			dm::uint32 id1:24;	// 0
		}u;

	}m_ctl;

	dm::uint8 m_asdu[MaxLenOfAsdu];

	apdu_t m_apduRef;
};

}
}



#endif /* INCLUDE_DM_FRAME_FRAME104LDU_HPP_ */
